#import "Controller.h"


@implementation Controller

-(void)bootRequest:(NSURLRequest*)request
{
    NSAutoreleasePool* myAutoreleasePool = [[NSAutoreleasePool alloc] init];

	NSHTTPURLResponse * response = nil;
	NSError * error = nil;
	
	NSData * data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
	
	if (data == nil)
	{
		[self flagURLError:@"Unable to make connection to URL."];
		m_urlData = nil;
	}
	else if (error)
	{
		[self flagURLError:[error localizedDescription]];
		m_urlData = nil;
	}
	else if ([response statusCode] != 200)
	{
		int code = [response statusCode];
		NSString * errorString = [NSString stringWithFormat:@"Unable to fetch page: %@", [NSHTTPURLResponse localizedStringForStatusCode:code]];

		[self flagURLError:errorString];
		m_urlData = nil;
	}
	else
	{
		m_urlData = [data retain];
	}
	
	[m_urlDataLock unlockWithCondition:1];
	
	[myAutoreleasePool release];
}

-(NSXMLDocument*)asyncFetchUrl:(NSURL*)url
{
	NSError *err = nil;

	m_urlDataLock = [[NSConditionLock alloc] initWithCondition:0];
	[m_urlDataLock lock];
	[progressIndicator startAnimation:nil];
	if (m_urlData)
	{
		[m_urlData release];
		m_urlData = nil;
	}
		
	NSURLRequest * request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:30.0];
	
	[NSThread detachNewThreadSelector:@selector(bootRequest:) toTarget:self withObject:request];
	
	// wait for the URL data to be fetched.
	[m_urlDataLock lockWhenCondition:1];
	[m_urlDataLock unlockWithCondition:0];

	[progressIndicator stopAnimation:nil];
	
	if (m_urlData == nil)
		return nil;
	
	NSXMLDocument * xmlDoc = [[NSXMLDocument alloc] initWithData:m_urlData
								options:NSXMLDocumentTidyXML
								error:&err];
	[m_urlData release];
	m_urlData = nil;
	
	return [xmlDoc autorelease];
}


-(void)flagURLError:(NSString*)errorString
{
	NSLog(@"Here: %s", __FUNCTION__);
	NSLog(@"Error: %@", errorString);
	[statusText setStringValue:[NSString stringWithFormat:@"An error occurred! %@", errorString]];
	[progressIndicator stopAnimation:nil];
}

-(void)setupCaches
{
	NSError *err = nil;
	
	m_regionsCache = [[NSMutableDictionary alloc] init];
	m_regionsArrayCache = [[NSMutableArray alloc] init];
	
	NSURL * myUrl = [NSURL URLWithString:@"http://d1.com.au/D1xmltv.asmx/GetRegions?"];
	// NSURL * myUrl = [NSURL URLWithString:@"file:///Users/hagus/boris.xml"];
	NSXMLDocument * xmlDoc = [self asyncFetchUrl:myUrl];
								
	NSArray * nodes = [xmlDoc nodesForXPath:@"//*[local-name()='NewDataSet']/*[local-name()='Regions']" error:&err];
	int i = 0;
	for (i = 0; i < [nodes count]; i++)
	{
		NSXMLElement * region = [nodes objectAtIndex:i];
		NSString * codeString = [[[region nodesForXPath:@"Code" error:&err] objectAtIndex:0] stringValue];
		NSString * description = [[[region nodesForXPath:@"Description" error:&err] objectAtIndex:0] stringValue];
		
		[m_regionsCache setObject:codeString forKey:description];
		[m_regionsArrayCache addObject:description];
		
		// NSLog(@"Code was %@", codeString);
		// NSLog(@"Description was %@", description);
	}
	
	
	m_providersCache = [[NSMutableDictionary alloc] init];
	m_providersArrayCache = [[NSMutableArray alloc] init];

	myUrl = [NSURL URLWithString:@"http://d1.com.au/D1xmltv.asmx/GetProviders?"];
	// myUrl = [NSURL URLWithString:@"file:///Users/hagus/GetProviders.xml"];
	xmlDoc = [self asyncFetchUrl:myUrl];
	
	nodes = [xmlDoc nodesForXPath:@"//*[local-name()='NewDataSet']/*[local-name()='Providers']" error:&err];
	i = 0;
	for (i = 0; i < [nodes count]; i++)
	{
		NSXMLElement * provider = [nodes objectAtIndex:i];
		NSString * codeString = [[[provider nodesForXPath:@"Code" error:&err] objectAtIndex:0] stringValue];
		NSString * description = [[[provider nodesForXPath:@"Description" error:&err] objectAtIndex:0] stringValue];
		
		[m_providersCache setObject:codeString forKey:description];
		[m_providersArrayCache addObject:description];
		
		NSLog(@"Code was %@", codeString);
		NSLog(@"Description was %@", description);
	}

}

-(NSDictionary*)getChannels:(NSString*)provider region:(NSString*)region
{
	NSError *err = nil;
	
	NSString * requestKey = [NSString stringWithFormat:@"%@:%@", provider, region];
	
	NSDictionary * returnDict = [m_channelsCache objectForKey:requestKey];
	if (returnDict != nil)
		return returnDict;
	
	if (!m_channelsCache)
	{
		m_channelsCache = [[NSMutableDictionary alloc] init];
	}
	
	NSString * requestUrl = [NSString stringWithFormat:@"http://d1.com.au/D1xmltv.asmx/GetChannels?provider=%@&region=%@", provider, region];
	NSLog(@"Request URL was %@", requestUrl);
	
	NSURL * myUrl = [NSURL URLWithString:requestUrl];
	NSXMLDocument * xmlDoc = [self asyncFetchUrl:myUrl];
								
	NSArray * nodes = [xmlDoc nodesForXPath:@"//*[local-name()='NewDataSet']/*[local-name()='Channels']" error:&err];
	NSLog(@"Found %d channels in data.", [nodes count]);
	int i = 0;
	NSMutableDictionary * channelListDict = [[NSMutableDictionary alloc] init];
	for (i = 0; i < [nodes count]; i++)
	{
		NSXMLElement * channel = [nodes objectAtIndex:i];
		NSString * channelNum = [[[channel nodesForXPath:@"Channel" error:&err] objectAtIndex:0] stringValue];
		NSString * channelID = [[[channel nodesForXPath:@"ChannelID" error:&err] objectAtIndex:0] stringValue];
		NSString * callsign = [[[channel nodesForXPath:@"Callsign" error:&err] objectAtIndex:0] stringValue];
		NSString * name = [[[channel nodesForXPath:@"Name" error:&err] objectAtIndex:0] stringValue];
		
		NSDictionary * tempDict = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:channelNum, channelID, callsign, name, nil] forKeys:[NSArray arrayWithObjects:@"Channel", @"ChannelID", @"Callsign", @"Name", nil]];
		
		[channelListDict setObject:tempDict forKey:name];
		
		// NSLog(@"Channel was %@", name);
		// NSLog(@"Description was %@", description);
	}
	
	[m_channelsCache setObject:channelListDict forKey:requestKey];
	
	return channelListDict;
}

-(NSArray*)getJustChannelNames:(NSString*)provider region:(NSString*)region
{
	NSDictionary * channelDict = [self getChannels:provider region:region];
	return [[channelDict allKeys] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
}


-(int)updateChannelData:(NSString*)channelid date:(NSDate*)date
{
	NSError *err = nil;
	
	if (m_tableData == nil)
		m_tableData = [[NSMutableArray alloc] init];
		
	[m_tableData removeAllObjects];
	
	NSString * formattedDate = [date descriptionWithCalendarFormat:@"%Y/%m/%d" timeZone:nil locale:nil];
	NSString * requestUrl = [NSString stringWithFormat:@"http://d1.com.au/D1xmltv.asmx/GetPrograms?channelid=%@&date=%@", channelid, formattedDate];
	NSLog(@"Now requesting %@", requestUrl);
	NSURL * myUrl = [NSURL URLWithString:requestUrl];
	
	NSXMLDocument * xmlDoc = [self asyncFetchUrl:myUrl];
	
	if (xmlDoc == nil)
		return 1;
									
	NSArray * nodes = [xmlDoc nodesForXPath:@"//*[local-name()='NewDataSet']/*[local-name()='Programs']" error:&err];
	int i = 0;
	for (i = 0; i < [nodes count]; i++)
	{
		NSMutableDictionary * rowDict = [[NSMutableDictionary alloc] init];
		NSXMLElement * region = [nodes objectAtIndex:i];
		NSString * title = [[[region nodesForXPath:@"Title" error:&err] objectAtIndex:0] stringValue];
		NSString * start = [[[region nodesForXPath:@"Start" error:&err] objectAtIndex:0] stringValue];
		NSString * stop = [[[region nodesForXPath:@"Stop" error:&err] objectAtIndex:0] stringValue];
		NSString * description = [[[region nodesForXPath:@"Description" error:&err] objectAtIndex:0] stringValue];
		NSString * category = [[[region nodesForXPath:@"Category" error:&err] objectAtIndex:0] stringValue];
		NSString * rating = @""; // [[[region nodesForXPath:@"Rating" error:&err] objectAtIndex:0] stringValue];
	
		NSCalendarDate * startCD = [NSCalendarDate dateWithString:start calendarFormat:@"%Y%m%d%H%M%S %z"];
		
		NSCalendarDate * stopCD = [NSCalendarDate dateWithString:stop calendarFormat:@"%Y%m%d%H%M%S %z"];
		
		double timeInterval = [stopCD timeIntervalSince1970] - [startCD timeIntervalSince1970];
		NSNumber * duration = [NSNumber numberWithInt:(timeInterval / 60)];
		
		
		/* NSString * testString = [startCD description];
		NSLog(@"%@", testString);
		NSDate * now = [NSDate date];
		NSString * sampleDate = [now descriptionWithCalendarFormat:@"%Y%m%d%H%M%S %z" timeZone:nil locale:nil];
		NSLog(@"%@", sampleDate); */
	
		[rowDict setObject:title forKey:@"title"];
		[rowDict setObject:[startCD descriptionWithCalendarFormat:@"%H:%M" timeZone:nil locale:nil] forKey:@"start"];
		[rowDict setObject:[stopCD  descriptionWithCalendarFormat:@"%H:%M" timeZone:nil locale:nil] forKey:@"stop"];
		[rowDict setObject:description forKey:@"description"];
		[rowDict setObject:category forKey:@"category"];
		[rowDict setObject:rating forKey:@"rating"];
		[rowDict setObject:duration forKey:@"duration"];
		
		// hidden ones that aren't displayed
		[rowDict setObject:startCD forKey:@"startCD"];
		[rowDict setObject:stopCD forKey:@"stopCD"];
		
		[m_tableData addObject:rowDict];
	}
	
	// NSLog(@"%@", [m_tableData description]);
	
	[programTable reloadData];
	
	return 0;
}

-(void)savePreferences
{
	NSLog(@"Saving preferences");
	NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
	[defaults setObject:m_regionsCache forKey:@"RegionsCache"];
	[defaults setObject:m_providersCache forKey:@"ProvidersCache"];
	[defaults setObject:m_regionsArrayCache forKey:@"RegionsArrayCache"];
	[defaults setObject:m_providersArrayCache forKey:@"ProvidersArrayCache"];
	[defaults setObject:m_channelsCache forKey:@"ChannelsCache"];
	[defaults synchronize];
}

-(void)restorePreferences
{
	NSLog(@"Restoring preferences");
	NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
	m_regionsCache = [[defaults objectForKey:@"RegionsCache"] mutableCopy];
	m_providersCache = [[defaults objectForKey:@"ProvidersCache"] mutableCopy];
	m_regionsArrayCache = [[defaults objectForKey:@"RegionsArrayCache"] mutableCopy];
	m_providersArrayCache = [[defaults objectForKey:@"ProvidersArrayCache"] mutableCopy];
	m_channelsCache = [[defaults objectForKey:@"ChannelsCache"] mutableCopy];
}

-(NSDictionary*)getInfoForCurrentChannel
{
	NSString * provider = [providersBox titleOfSelectedItem];
	NSString * region = [regionsBox titleOfSelectedItem];
	NSString * realProvider = [m_providersCache objectForKey:provider];
	NSString * realRegion = [m_regionsCache objectForKey:region];
	NSString * requestKey = [NSString stringWithFormat:@"%@:%@", realProvider, realRegion];
	
	NSString * selectedChannel = [channelsBox titleOfSelectedItem];
	return [[m_channelsCache objectForKey:requestKey] objectForKey:selectedChannel];	
}


///// ---- NIB ROUTINES ---- //////



- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
	[self restorePreferences];
	
	if (m_regionsCache == nil || m_regionsArrayCache == nil ||
		m_providersCache == nil || m_providersArrayCache == nil)
	{
		[self setupCaches];
	}
	
	[dateBox setDateValue:[NSDate date]];
	
	[regionsBox removeAllItems];
	[regionsBox addItemsWithTitles:[m_regionsArrayCache sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)]];
	[regionsBox selectItemWithTitle:@"NSW - Sydney"];
	
	[providersBox removeAllItems];
	[providersBox addItemsWithTitles:[m_providersArrayCache sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)]];
	[providersBox selectItemWithTitle:@"Free to View Digital"];
	
	NSArray * channelsList = [self getJustChannelNames:@"freesd" region:@"Sydney"];
	[channelsBox removeAllItems];
	[channelsBox addItemsWithTitles:channelsList];
	
	if ([self updateChannelData:@"freesd.Sydney.7" date:[NSDate date]] == 0)
		[statusText setStringValue:@"Welcome to Hagus' EPG."];
}

-(id)tableView:(NSTableView*)aTableView objectValueForTableColumn:(NSTableColumn*)aTableColumn row:(int)row   
{   
    NSParameterAssert(row  >= 0 && row < [m_tableData count]);
    
    id record = [m_tableData objectAtIndex:row];
    id theValue = [record objectForKey:[aTableColumn identifier]];
    return theValue;
}   

-(int)numberOfRowsInTableView:(NSTableView*)aTableView
{
 //   NSLog(@"Rows in table: %d", [m_tableData count]);
    return [m_tableData count];
}

- (void)windowWillClose:(NSNotification *)notification
{
	NSLog(@"Window closing");
	[self savePreferences];

}

-(void)applicationWillTerminate:(NSNotification *)notification 
{
	NSLog(@"Goodbye from epg");
//	[self savePreferences];
//	NSLog(@"Goodbye from epg");
}


-(void)providersRegionChanged:(id)sender
{
	NSString * provider = [providersBox titleOfSelectedItem];
	NSString * region = [regionsBox titleOfSelectedItem];
	NSString * realProvider = [m_providersCache objectForKey:provider];
	NSString * realRegion = [m_regionsCache objectForKey:region];
	
	NSArray * channelsList = [self getJustChannelNames:realProvider region:realRegion];
	[channelsBox removeAllItems];
	[channelsBox addItemsWithTitles:channelsList];
}

-(void)channelChanged:(id)sender
{
	// grab the provider and region, and switch channels.
//	NSLog(@"Channel Changed");
	
	NSString * provider = [providersBox titleOfSelectedItem];
	NSString * region = [regionsBox titleOfSelectedItem];
	NSString * realProvider = [m_providersCache objectForKey:provider];
	NSString * realRegion = [m_regionsCache objectForKey:region];
	
	NSString * requestKey = [NSString stringWithFormat:@"%@:%@", realProvider, realRegion];
	
	NSString * selectedChannel = [channelsBox titleOfSelectedItem];
	NSDictionary * channelDict = [[m_channelsCache objectForKey:requestKey] objectForKey:selectedChannel];
	
	if ([self updateChannelData:[channelDict objectForKey:@"ChannelID"] date:[dateBox dateValue]] == 0)
	{
		[statusText setStringValue:[NSString stringWithFormat:@"%@, on date %@, in %@, for %@.",
			[channelsBox titleOfSelectedItem], [[dateBox dateValue] descriptionWithCalendarFormat:@"%Y/%m/%d" timeZone:nil locale:nil],
			[regionsBox titleOfSelectedItem], [providersBox titleOfSelectedItem]]];
	}
	
	// take the current channel
}

-(void)addProgramButton:(id)sender
{
	NSLog(@"Add program button.");
	
	// find the currently selected channel and the currently selected program.
	int row = [programTable selectedRow];
	NSDictionary * programInfo = [m_tableData objectAtIndex:row];
	NSDictionary * channelInfo = [self getInfoForCurrentChannel];
	
	NSCalendarDate * startDate = [programInfo objectForKey:@"startCD"];
	int duration = [[programInfo objectForKey:@"duration"] intValue];
	duration *= 60; // seconds
	NSString * description = [programInfo objectForKey:@"category"];
	
	NSString * title = [programInfo objectForKey:@"title"];
	NSString * channelNumber = [channelInfo objectForKey:@"Channel"];
	NSString * stationName = [channelInfo objectForKey:@"Name"];
	
	
	// NSLog(@"start date %@, duration %d", [startDate descriptionWithCalendarFormat:@"%Y/%m/%d"], duration);
	// NSLog(@"title %@, channel number %@, station name %@", title, channelNumber, stationName);
	
	NSAppleScript * addScript;
	NSString * appleScriptSource = [NSString stringWithFormat:@"tell application \"EyeTV\"\n make new program with properties {start time:date \"%@\", duration:\"%d\", title:\"%@\", description:\"%@\", station name:\"%@\", channel number:\"%@\", quality:\"%@\"}\n end tell", [startDate descriptionWithCalendarFormat:@"%d %B %Y %H:%M:%S %p"], duration, title, description, stationName, channelNumber, @"high"];
	
	NSLog(@"would have done - %@", appleScriptSource);
	
	addScript = [[NSAppleScript alloc] initWithSource:appleScriptSource];
	[addScript executeAndReturnError:nil];
}

-(void)datePickerChanged:(id)sender
{
	NSLog(@"Date picker changed");
	[self channelChanged:nil];
}

-(void)aboutSelected:(id)sender
{
	NSLog(@"About selected");
	[aboutPanel center];
	[aboutPanel orderFront:self];
	
}

-(void)visitHomepageClicked:(id)sender
{
	NSLog(@"Visit homepage clicked");
	[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://www.hagus.net"]];
}

@end
